/**
 *
 * Copyright 2009 Bill Garrett (memesis@gmail.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use
 * this file except in compliance with the License.  You may obtain a copy of the
 * License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software distributed
 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
 * language governing permissions and limitations under the License. 
 */
package org.memesis.pandorasbook;

import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeSet;

import javax.jms.JMSException;

import org.apache.bsf.BSFException;
import org.apache.bsf.BSFManager;
import org.apache.bsf.util.IOUtils;
import org.memesis.pandorasbook.util.ExceptionHandler;

/**
 * An applet which loads one or more scripts specified in its manifest.
 * This incarnation of the applet uses BSF as its scripting engine.
 *
 * @author garrett
 */
public class ScriptApplet implements PandoraApplet {
	private HashMap<String, String> properties;
	private BSFManager manager;
	private PandoraDesktop desktop;
	private PandoraMessageQueue mq;
	
	/**
	 * Default constructor.
	 */
	public ScriptApplet() {
		properties = new HashMap<String, String>();
		manager = new BSFManager();
		mq = null;
	}
	
	/**
	 * Assigns this applet its Desktop object after construction.
	 * 
	 * @param desk the Desktop object in use by the system
	 */
	public void setDesktop(PandoraDesktop desk) {
		desktop = desk;
	}
	
	/**
	 * Returns the map of properties in use by the applet.  Each script
	 * is free to use its properties as it sees fit.
	 * 
	 * ScriptApplet requires a "script" property pointing to the URL
	 * of some BSF-compatible script.
	 */
	public Map<String, String> getProperties() {
		return properties;
	}

	/**
	 * Returns a named property.  A convenience method.
	 */
	public String getProperty(String key) {
		return properties.get(key);
	}

	/**
	 * Execute a BSF-compatible script.  Each script has two global objects
	 * available to it: "applet", containing this object, and "frame",
	 * containing an instance of PandoraAppletFrame in which the applet
	 * is being run.  A third global, "mq", exists if the applet exposed
	 * a "jms-url" property.
	 */
	public void startApplet(PandoraAppletFrame frame) {
		try {
			mq = new PandoraMessageQueue(this);
			
			manager.declareBean("applet", this, this.getClass());
			manager.declareBean("frame", frame, frame.getClass());
			manager.declareBean("mq", mq, mq.getClass());
			
			URL appletUrl = new URL(getProperty("pandorasbook-applet-url"));

			for(String propertyName : new TreeSet<String>(getProperties().keySet())) {
				if(propertyName.startsWith("script")) {
					executeScriptFromUrl(new URL(appletUrl, getProperty(propertyName)));
				}
			}
		} catch (IOException ex) {
			ExceptionHandler.reportException(ex);
		} catch (BSFException ex) {
			ExceptionHandler.reportException(ex);
		} catch (JMSException ex) {
			ExceptionHandler.reportException(ex);
		}
	}

	/**
	 * Terminates the BSF script manager.
	 */
	public void stopApplet() {
		manager.terminate();
		if(null != mq)
			mq.terminate();
	}
	
	private void executeScriptFromUrl(URL scriptSource) throws BSFException, IOException {
		String scriptingLanguage = BSFManager.getLangFromFilename(scriptSource.getFile());
		String scriptContents = IOUtils.getStringFromReader(new InputStreamReader(scriptSource.openStream()));
		manager.exec(scriptingLanguage, scriptSource.toString(), 0, 0, scriptContents);
	}

	/**
	 * Permits scripts to open other applets in the desktop.
	 */
	public PandoraApplet runApplet(String targetUrl) throws MalformedURLException {
		return runApplet(targetUrl, null);
	}

	/**
	 * Permits scripts to open other applets in the desktop.
	 */
	public PandoraApplet runApplet(String targetUrl, Map<String, String> newProps) throws MalformedURLException {
		HashMap<String, String> newMap;
		
		newMap = new HashMap<String, String>();

		newMap.put("pandorasbook-applet-url", getProperty("pandorasbook-applet-url"));
		
		if (newProps != null) {
			newMap.putAll(newProps);
		}
		return desktop.runApplet(targetUrl, newMap);
	}

}